import logging
from datetime import datetime
import random
from typing import Any

from django.contrib.auth import authenticate
from django.contrib.auth.hashers import check_password, make_password
from ninja.responses import Response
from ninja_extra.exceptions import APIException
from ninja_jwt.tokens import SlidingToken
from ninja_jwt.controller import TokenObtainSlidingController
from ninja_extra import api_controller, route, status

from QQLoginTool.QQtool import OAuthQQ

from oauth.models import OAuthQQUser
from .schema import QQUserInSchema

from users.schemas import UserSchemaOut, UserTokenOutSchema
from users.models import User
from meiduo_mall.base.schemas import Message
from carts.utils import merge_cookie_redis

logger = logging.getLogger('django')


@api_controller('/qq', tags=['QQ登录'])
class QQAuthController:
    def __init__(self):
        self.oauth = OAuthQQ

    # @http_get('/auth', summary='QQ认证')    看源码：http_get = route.get
    @route.get('/auth', summary='QQ认证')
    def qq_auth(self):
        # 1.获取QQ登录前的地址
        # next = self.context.request.GET.get('next') if self.context.request.GET.get('next') else '/'
        next = self.context.request.GET.get('next', '/')
        # 2.QQ登录SDK实例化
        # 获取QQ登录⻚页⾯面⽹网址
        # 登录参数，应该配置在settings.py中，暂时放这里
        QQ_CLIENT_ID = '101514053'
        QQ_CLIENT_SECRET = '1075e75648566262ea35afa688073012'
        QQ_REDIRECT_URL = 'http://127.0.0.1:5500/oauth_callback.html'
        oauth = self.oauth(client_id=QQ_CLIENT_ID, client_secret=QQ_CLIENT_SECRET, redirect_uri=QQ_REDIRECT_URL,
                           state=next)
        # 3.调用实例方法，拼接login_url:qq扫码登录网址
        # login_url = oauth.get_qq_url()
        # 没有QQ登录，用回调地址代替,传回state,方便前端跳转
        return {'login_url': f'{QQ_REDIRECT_URL}?state={next}'}

    @route.get('/login', summary='QQ登录', )
    def qq_login(self):
        # 获取前端传入code
        code = self.context.request.GET.get(
            'code')  # if self.context.request.GET.get('code') else random.randint(1, 99)
        if not code:
            return 400, {'msg': 'QQ认证失败，请重试'}
        # # 创建QQ登录工具对象
        # 如果没有开通QQ登录则注释下面QQ登录的try
        # QQ登录
        # try:
        #     # 调用get_access_token(code)方法，用code向QQ服务器获取access_token
        #     access_token = self.oauth.get_access_token(code)
        #     # 调用get_open_id(access_token) 用access_token向QQ服务器获取open_id
        #     open_id = self.oauth.get_open_id(access_token)
        # except Exception as e:
        #     logger.info(e)
        #     return 400, {'msg': '服务不可用，请重试'}
        # QQ登录
        # 向数据库校验open_id是否存在，存在登录成功，则返回JWT信息，否则进行绑定登记
        try:
            QQUser = OAuthQQUser.objects.get(openid=code)
        except OAuthQQUser.DoesNotExist:
            # 未绑定过QQ
            # 通过django的make_password对code加密返回给前端
            openid = make_password(str(code))
            """
            self.context.request.session[openid] = code
            把加密后的code作为键存到session中
            """
            self.context.request.session[openid] = code
            return 200, {'msg': openid}

        else:
            user_obj = QQUser.user
            # 生成令牌
            token = SlidingToken.for_user(user_obj)
            data = UserTokenOutSchema(
                user=user_obj,
                token=str(token),
                token_exp_date=datetime.fromtimestamp(token["exp"])
            )
            response = Response(status=200, data=data)
            merge_cookie_redis(self.context.request, user_obj, response)
            return response

    @route.post('/qq-auth-id', summary='账号绑定QQ', response={200: UserTokenOutSchema, 400: Message})
    def qq_openid(self, data: QQUserInSchema):
        """
        code = self.context.request.session.get(data.access_token)
        通过前端传回的access_token来取code
        """
        code = self.context.request.session.get(data.access_token)
        del self.context.request.session[data.access_token]
        if not check_password(str(code), data.access_token):
            return 400, {'msg': 'QQ号有误，请核对'}

        # 手机号未注册
        try:
            user = User.objects.get(mobile=data.mobile)
        except User.DoesNotExist:
            # 保存QQ与user绑定表
            user_obj = User.objects.create(username=data.mobile, mobile=data.mobile,
                                           password=make_password(data.password))
            OAuthQQUser.objects.create(openid=code, user=user_obj)
            token = SlidingToken.for_user(user_obj)

            data = UserTokenOutSchema(
                user=user_obj,
                token=str(token),
                token_exp_date=datetime.fromtimestamp(token["exp"])
            )
            response = Response(status=200, data=data)
            merge_cookie_redis(self.context.request, user_obj, response)
            return response

        # 手机号已注册
        else:
            # 返回JWT
            OAuthQQUser.objects.create(openid=code, user=user)
            token = SlidingToken.for_user(user)
            data = UserTokenOutSchema(
                user=user,
                token=str(token),
                token_exp_date=datetime.fromtimestamp(token["exp"])
            )
            response = Response(status=200, data=data)
            merge_cookie_redis(self.context.request, user, response)
            return response
